home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / dns / ddt2.0 / cmd / rrc < prev    next >
Encoding:
Text File  |  1993-05-27  |  15.0 KB  |  741 lines

  1. #! /usr/local/bin/perl
  2. #
  3. #  rrc - resource records checker
  4. #
  5. #  invoke as:
  6. #    rrc [-l msglevel]
  7. #
  8. #  Copyright (C) 1992, 1993 PUUG - Grupo Portugues de Utilizadores
  9. #                   do Sistema UNIX
  10. #             1992, 1993 FCCN - Fundacao para o Desenvolvimento dos Meios 
  11. #                        Nacionais de Calculo Cientifico     
  12. #
  13. #  Authors: Jorge Frazao de Oliveira <frazao@puug.pt>
  14. #        Artur Romao <artur@dns.pt>
  15. #
  16. #  This file is part of the DDT package, Version 2.0.
  17. #
  18. #  Permission to use, copy, modify, and distribute this software and its 
  19. #  documentation for any purpose and without any fee is hereby granted, 
  20. #  provided that the above copyright notice appear in all copies.  Neither 
  21. #  PUUG nor FCCN make any representations about the suitability of this
  22. #  software for any purpose.  It is provided "as is" without express or 
  23. #  implied warranty.
  24.  
  25.  
  26. # =()<push(@INC, "@<LIBDIR>@");>()=
  27. push(@INC, "/usr/local/lib/ddt/cmd");
  28.  
  29. require "ddt.pl";
  30.  
  31.  
  32. while (<STDIN>) {
  33.     next if /^;\s+Ignoring info/;    # if commented lines are not 
  34.                     # of this form
  35.     s/^; //;                # check them too
  36.  
  37.     chop;                # strip record separator
  38.     @Field = split(/\s+/, $_);    # break the input line
  39.  
  40.     if (/^\$ORIGIN/) {
  41.         $Origin = $Field[2];    # set to a different origin
  42.     
  43.         next;
  44.     }
  45.  
  46.         if (/^[*\.\-0-9A-Za-z]+/) { 
  47.         $LineName = 1;
  48.  
  49.         $Name = &make_name($Field[1], $Origin);
  50.     }
  51.  
  52.         if (/\tIN\tSOA\t/) {
  53.         $Zone = &tolower($Name);
  54.  
  55.         if ($Line[$#Line] eq '(') {
  56.             &SOA_RR($Zone, $Field[$#Field - 2]); 
  57.  
  58.                    <STDIN>;    # skip the line defining the timers
  59.         }
  60.         else {
  61.             &SOA_RR($Zone, $Field[$#Field - 7]);
  62.         }
  63.     }
  64.     elsif (/\tIN\tNS\t/) {
  65.         &NS_RR($Zone, $Name, $Field[$#Field]);
  66.     }
  67.         elsif (/\tIN\tWKS\t*([*\.\-0-9A-Za-z]+)/) {
  68.         &WKS_RR($Zone, $Name, $1);
  69.         }
  70.     elsif (/\tIN\tCNAME\t/) {
  71.         &CNAME_RR($Zone, $Name, $Field[$#Field]);
  72.         }
  73.         elsif (/\tIN\tA\t/) {
  74.         &A_RR($Zone, $Name, $Field[$#Field]);
  75.         }
  76.         elsif (/\tIN\tPTR\t/) {
  77.         &PTR_RR($Zone, $Name, $Field[$#Field]);
  78.         }
  79.         elsif (/\tIN\tMX\t/) {
  80.         &MX_RR($Zone, $Name, $Field[$#Field]);
  81.         }
  82.         elsif ($LineName) {    # it only makes sense to check on these if
  83.         $LineName = 0;    # they're related to a new name, or else
  84.                 # "someone" has already done it
  85.         if(/\tIN\tHINFO\t/) {
  86.             &HINFO_RR($Zone, $Name);
  87.             }
  88.             elsif (/\tIN\tTXT\t/) {
  89.             &TXT_RR($Zone, $Name);
  90.             }
  91.     }
  92. }
  93.  
  94. &check_RR();
  95.  
  96. exit(0);
  97.  
  98.  
  99. sub perror_notation {
  100.         local($name) = @_;
  101.  
  102.         if ($Level >= 3) {
  103.         print "$Lpad[3]Hostname $name should be in domain notation";
  104.         }
  105. }
  106.  
  107.  
  108. sub perror_no_data {
  109.         local($name, $zone) = @_;
  110.  
  111.            if (&in_THIS_zone($name, $zone)) {
  112.         if (Level >= 2) {
  113.                        print "$Lpad[2]No A/CNAME records found for $name";
  114.             }
  115.     }
  116.         elsif ($Level >= 4) {
  117.         print "$Lpad[4]No A/CNAME records found for $name [Can't verify it]";
  118.         }
  119. }
  120.  
  121.  
  122. sub perror_trailing_dot {
  123.         local($name) = @_;
  124.  
  125.         if ($Level >= 3) {
  126.         print "$Lpad[3]Perhaps name without a trailing dot: $name"; 
  127.         }
  128. }
  129.  
  130.  
  131. sub perror_address_mismatch {    
  132.     local($address, $name, $zone) = @_;
  133.  
  134.         if (&in_THIS_zone($name, $zone)) {
  135.             if ($Level >= 3) {
  136.                     print "$Lpad[3]$address/$name mismatch in a WKS record";
  137.             }
  138.         }
  139.         elsif ($Level >= 4) {
  140.             print "$Lpad[4]$address/$name mismatch in a WKS record [Can't verify it]";
  141.         }
  142. }
  143.  
  144.  
  145. sub perror_subzone_ns {
  146.         local($zone) = @_;
  147.  
  148.         if ($Level >= 4) {
  149.         print "$Lpad[4]Can't verify if NS RRs for $zone are correct";
  150.         }
  151. }
  152.  
  153.  
  154. sub perror_missing_ns {
  155.         local($server, $zone) = @_;
  156.  
  157.         if ($Level >= 1) {
  158.         print "$Lpad[1]$server is not a valid name server for $zone"; 
  159.         }
  160. }
  161.  
  162.  
  163. sub perror_extra_ns {
  164.         local($server, $zone) = @_;
  165.     local(@label, $upzone);
  166.  
  167.         if ($Level >= 2) {
  168.         @label = split(/\./, $zone);
  169.         shift(@label);
  170.         $upzone = join(".", @label) . ".";
  171.  
  172.         print "$Lpad[2]$server is not defined as name server for $zone in $upzone";
  173.         }
  174. }
  175.  
  176.  
  177. sub perror_reserved_name_error {
  178.         local($host, $zone) = @_;
  179.  
  180.         if ($Level >= 1) {
  181.             print "$Lpad[1]This name may introduce a severe problem: $host"; 
  182.         }
  183. }
  184.  
  185.  
  186. sub perror_reserved_name_warn {
  187.         local($host) = @_;
  188.  
  189.         if ($Level >= 3) {
  190.             print "$Lpad[3]You should avoid the use of this reserved name: $host";
  191.         }
  192. }
  193.  
  194.  
  195. sub perror_mult_ip {
  196.     local($address) = @_;
  197.  
  198.     if ($Level >= 3) {
  199.         $names = $Names{$address};
  200.         $names =~ s/$LISTsep/$LISTsep /g;
  201.  
  202.         print "$Lpad[3]There are several hosts with address $address: $names";
  203.     }
  204. }
  205.  
  206.  
  207. sub perror_mult_revip {
  208.     local($address) = @_;
  209.  
  210.     if ($Level >= 3) {
  211.         $names = $RevNames{$address};
  212.         $names =~ s/$LISTsep/$LISTsep /g;
  213.  
  214.         print "$Lpad[3]There are several names mapped into $address: $names";
  215.     }
  216. }
  217.  
  218.  
  219. sub perror_alias_chain {
  220.     local($alias, $name) = @_;
  221.  
  222.     if ($Level >= 4) {
  223.         print "$Lpad[4]Alias $alias points to another alias: $name";
  224.     }
  225. }
  226.  
  227.  
  228. sub perror_alias {
  229.     local($alias) = @_;
  230.  
  231.     if ($Level >= 3) {
  232.         print "$Lpad[3]Alias $alias used where a canonical name should appear";
  233.     }
  234. }
  235.  
  236. #
  237. # check if this is a "missing trailing dot" problem
  238. #
  239. sub missing_trailing_dot {
  240.         local($name, $zone) = @_;
  241.     local($s) = "[.]";
  242.  
  243.         $zone = "." . $zone;
  244.         $zone =~ s/$s/[.]/g;
  245.  
  246.         if (($name =~ $zone) && (length($`) + length($&) != length($name))) {
  247.                 &perror_trailing_dot($name);
  248.         }
  249. }
  250.  
  251.  
  252. #
  253. # is there anything leading us to this $name?
  254. #
  255. sub has_data {
  256.         local($name) = @_;
  257.  
  258.         return defined $Addresses{$name} || $IsAlias{$name};
  259. }
  260.  
  261.  
  262. #
  263. # a $name in dot-quad notation!!
  264. #
  265. sub internet_address_format {
  266.         local($name) = @_;
  267.     
  268.     return $name =~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\.$/;
  269. }
  270.  
  271.  
  272. #
  273. # $name is one of the names one shouldn't use in RR's
  274. #
  275. sub is_reserved_name {
  276.         local($name) = @_;
  277.  
  278.         return $name =~ /^localhost/ || 
  279.                $name =~ /^loopback/  || 
  280.                $name =~ /^127[.]0[.]0[.]1/ ||
  281.            $name =~ /^1.0.0.127.in-addr.arpa/;
  282. }
  283.  
  284.  
  285. #
  286. # in this case the reserved-name problem can be really serious...
  287. #
  288. sub reserved_name_error {
  289.         local($name, $zone) = @_;
  290.  
  291.          if (&is_reserved_name($name) && !$ResNameError{$name, $zone}++) {
  292.                &perror_reserved_name_error($name);
  293.         }
  294. }
  295.  
  296.  
  297. #
  298. # ... but here we only warn about it
  299. #
  300. sub reserved_name_warn {
  301.         local($host, $zone) = @_;
  302.     
  303.     if (&is_reserved_name($host) && !$ResNameWarn{$name, $zone}++) {
  304.         &perror_reserved_name_warn($host);
  305.         }
  306. }
  307.  
  308.  
  309. #
  310. # $address is really one of $name's addresses
  311. #
  312. sub ip_address_match {
  313.     local($address, $name) = @_;
  314.  
  315.     return &in($address, $Addresses{$name}, $LISTsep);
  316. }
  317.  
  318.  
  319. #
  320. # fetch the name servers for $zone
  321. #
  322. sub get_zone_ns {
  323.         local($zone) = @_;
  324.         local(@myNS, $name, $server, $NSlist);
  325.  
  326.     # get the NS as defined in $zone...
  327.         @myNS = split($LISTsep, $NS{$zone});
  328.  
  329.     while (@myNS) {
  330.             ($name, $server) = split($ELEMsep1, shift(@myNS));
  331.  
  332.         if ($name eq $zone) {    # ... but check only those 
  333.                     # for $zone itself
  334.             $NSlist = &add_list($NSlist,$server);
  335.         }
  336.     }
  337.         return $NSlist;
  338. }
  339.  
  340.  
  341. #
  342. # warn about a CNAME pointing to a CNAME
  343. #
  344. sub check_alias_chain {
  345.     local($alias, $name) = @_;
  346.  
  347.     if ($IsAlias{$name}) {
  348.         &perror_alias_chain($alias, $name);
  349.     }
  350. }
  351.  
  352.  
  353. #
  354. # warn about aa alias used where it is advisable to have a canonical
  355. # name, i.e., everywhere except on the left side of a CNAME RR
  356. #
  357. sub check_alias {
  358.     local($name, $zone) = @_;
  359.  
  360.     if ($IsAlias{$name} && !$AliasError{$name,  $zone}++) {
  361.         &perror_alias($name);
  362.     }
  363. }
  364.  
  365.  
  366. #
  367. # see if there are several names having this $address
  368. #
  369. sub check_unique_ip {
  370.     local($address, $zone) = @_;
  371.     local(@namelist);
  372.  
  373.     if (!$MultIPError{$address, $zone}++) {    # report this only once
  374.         @namelist = split($LISTsep, $Names{$address});
  375.  
  376.         if ($#namelist > 1) {
  377.             &perror_mult_ip($address);
  378.         }
  379.     }            
  380. }
  381.  
  382.  
  383. #
  384. # see if the same PTR RR is used to map more than one name
  385. #
  386.  
  387. sub check_unique_revip {
  388.     local($address, $zone) = @_;
  389.         local(@namelist);
  390.  
  391.         if (!$MultRevIPError{$address, $zone}) {   # report this only once
  392.                 $MultRevIPError{$address, $zone} = 1;
  393.  
  394.                 @namelist = split($LISTsep, $RevNames{$address});
  395.  
  396.                 if ($#namelist > 1) {
  397.                         &perror_mult_revip($address);
  398.                 }
  399.         }
  400.  
  401. }
  402.  
  403. #
  404. # look for some problems with this hostname
  405. #
  406. sub check_hostname {
  407.         local($name, $zone) = @_;
  408.  
  409.         if (&internet_address_format($name)) {
  410.         &perror_notation($name);
  411.         return 0;
  412.         }
  413.         elsif (!&has_data($name) && !$NoData{$name, $zone}++) {    
  414.             &perror_no_data($name, $zone);        # report this only once
  415.             return 0;
  416.     }
  417.     
  418.         return 1;
  419. }
  420.  
  421.  
  422. #
  423. # check delegation information for inconsistensies
  424. #
  425. sub check_delegate {
  426.     local(*subzones, $zone) = @_;
  427.     local($subzn, $zonens, $myzonens, @myservers, @realservers);
  428.     local($svr, $server);
  429.  
  430.         foreach $subzn (keys %subzones) {
  431.         if (defined $NS{$subzn}) {
  432.             $myzonens  = $subzones{$subzn};
  433.                 $zonens    = &get_zone_ns($subzn);
  434.  
  435.             # the NS list for $subzn, as seen by $zone
  436.                 @myservers = split($LISTsep, $myzonens);
  437.  
  438.             while ($server = shift(@myservers)) {
  439.                 if (!&in($server, $zonens, $LISTsep)) {
  440.                         &perror_missing_ns($server, $subzn);
  441.                 }
  442.                 }
  443.  
  444.             # the NS list for $subzn, as seen by $subzn
  445.                 @realservers = split($LISTsep, $zonens);
  446.  
  447.             while ($server = shift(@realservers)) {
  448.                 if (!&in($server, $myzonens, $LISTsep)) {
  449.                         &perror_extra_ns($server, $subzn);
  450.                 }
  451.                 }
  452.         }
  453.         else {
  454.                 &perror_subzone_ns($subzn);
  455.         }
  456.         }
  457. }
  458.  
  459.  
  460. #
  461. # take a look at all those RR's and report what's wrong woth them
  462. #
  463. sub check_RR {
  464.     local($zone);
  465.     local(@SOAlist, @NSlist, @CNAMElist, @Alist);
  466.     local(@WKSlist, @HINFOlist, @TXTlist, @MXlist);
  467.  
  468.         foreach $zone (keys %SOA) {
  469.         print "\n\n ###", &toupper($zone), "###\n";
  470.  
  471.         @SOAlist = $SOA{$zone};
  472.         &check_SOA($zone, *SOAlist);
  473.         undef %SOAlist;
  474.     
  475.         @NSlist = split($LISTsep, $NS{$zone});
  476.         &check_NS($zone, *NSlist);
  477.         undef %NSlist;
  478.     
  479.         @CNAMElist = split($LISTsep, $CNAME{$zone});
  480.         &check_CNAME($zone, *CNAMElist);
  481.         undef %CNAMElist;
  482.  
  483.         @Alist = split($LISTsep, $A{$zone});
  484.         &check_A($zone, *Alist);
  485.         undef %Alist;
  486.  
  487.         @PTRlist = split($LISTsep, $PTR{$zone});
  488.         &check_PTR($zone, *PTRlist);
  489.         undef %PTRlist;
  490.  
  491.         @WKSlist = split($LISTsep, $WKS{$zone});
  492.         &check_WKS($zone, *WKSlist);
  493.         undef %WKSlist;
  494.  
  495.         @HINFOlist = split($LISTsep, $HINFO{$zone});
  496.         &check_HINFO($zone, *HINFOlist);
  497.         undef %HINFOlist;
  498.  
  499.         @TXTlist = split($LISTsep, $TXT{$zone});
  500.         &check_TXT($zone, *TXTlist);
  501.         undef %TXTlist;
  502.  
  503.         @MXlist = split($LISTsep, $MX{$zone});
  504.         &check_MX($zone, *MXlist);
  505.         undef %MXlist;
  506.         }
  507. }
  508.  
  509.  
  510. sub check_SOA {
  511.         local($zone, *SOAlist) = @_;
  512.     local($origin);
  513.  
  514.     while ($origin = shift(@SOAlist)) {
  515.         &missing_trailing_dot($origin, $zone);
  516.             &reserved_name_error($origin, $zone);
  517.             &check_hostname($origin, $zone);
  518.         &check_alias($origin, $zone);
  519.     }
  520. }
  521.  
  522.  
  523. sub check_NS {
  524.         local($zone, *NSlist) = @_;
  525.     local($name, $server, @subzones);
  526.  
  527.     undef %subzones;
  528.  
  529.     while (@NSlist) {
  530.         ($name, $server) = split($ELEMsep1, shift(@NSlist));
  531.  
  532.         &missing_trailing_dot($name, $zone);
  533.         &reserved_name_warn($name, $zone);
  534.  
  535.         &missing_trailing_dot($server, $zone);
  536.         &reserved_name_error($server, $zone);
  537.         &check_hostname($server, $zone);
  538.         &check_alias($server, $zone);
  539.  
  540.         # create an NS list for each of our sub-zones, 
  541.         # to check on their consistency later
  542.         if ($name ne $zone) {
  543.                 $subzones{$name} = &add_list($subzones{$name}, $server);
  544.         }
  545.        }
  546.  
  547.     &check_delegate(*subzones, $zone);
  548. }
  549.  
  550.  
  551. sub check_CNAME {
  552.         local($zone, *CNAMElist) = @_;
  553.     local($alias, $name);
  554.  
  555.     while (@CNAMElist) {
  556.         ($alias, $name) = split($ELEMsep1, shift(@CNAMElist));
  557.  
  558.         &missing_trailing_dot($alias, $zone);
  559.         &reserved_name_warn($alias, $zone);
  560.  
  561.         &missing_trailing_dot($name, $zone);
  562.         &reserved_name_warn($name, $zone);
  563.         &check_hostname($name, $zone);
  564.         &check_alias_chain($alias, $name);
  565.         }
  566. }
  567.  
  568.  
  569. sub check_A {
  570.         local($zone, *Alist) = @_;
  571.     local($name);
  572.  
  573.     while (@Alist) {
  574.         ($name, $address) = split($ELEMsep1, shift(@Alist));
  575.  
  576.         &missing_trailing_dot($name, $zone);
  577.         &check_alias($name, $zone);        
  578.  
  579.         &check_unique_ip($address, $zone);
  580.         }
  581. }
  582.  
  583.  
  584. sub check_PTR {
  585.     local($zone, *PTRlist) = @_;
  586.     local($address);
  587.  
  588.     while(@PTRlist) {
  589.         ($address, $name) = split($ELEMsep1, shift(@PTRlist));
  590.  
  591.         &check_unique_revip($address, $zone);
  592.  
  593.         &missing_trailing_dot($name, $zone);
  594.         &check_alias($name, $zone);
  595.     }
  596. }
  597.  
  598. sub check_WKS {
  599.         local($zone, *WKSlist) = @_;
  600.     local($name, $address);
  601.  
  602.     while (@WKSlist) {
  603.         ($name, $address) = split($ELEMsep1, shift(@WKSlist));
  604.         
  605.         &missing_trailing_dot($name, $zone);
  606.         &reserved_name_warn($name, $zone);
  607.         &check_alias($name, $zone);
  608.         if (&check_hostname($name, $zone) &&
  609.                 !&ip_address_match($address, $name)) {
  610.             &perror_address_mismatch($address, $name, $zone);
  611.         }
  612.         }
  613. }
  614.  
  615.  
  616. sub check_HINFO {
  617.         local($zone, *HINFOlist) = @_;
  618.     local($name);
  619.  
  620.     while ($name = shift(@HINFOlist)) {
  621.         &missing_trailing_dot($name, $zone);
  622.         &reserved_name_warn($name, $zone);
  623.         &check_hostname($name, $zone);
  624.         &check_alias($name, $zone);
  625.         }
  626. }
  627.  
  628.  
  629. sub check_MX {
  630.         local($zone, *MXlist) = @_;
  631.     local($name, $pointer);
  632.  
  633.     while (@MXlist) {
  634.         ($name, $pointer) = split($ELEMsep1, shift(@MXlist));
  635.  
  636.         &missing_trailing_dot($name, $zone);
  637.             &reserved_name_warn($name, $zone);
  638.  
  639.             &missing_trailing_dot($pointer, $zone);
  640.             &reserved_name_error($pointer, $zone);
  641.             &check_hostname($pointer, $zone);
  642.         }
  643. }
  644.  
  645.  
  646. sub check_TXT {
  647.         local($zone, *TXTlist) = @_;
  648.         local($name);
  649.  
  650.     while ($name = shift(@TXTlist)) {
  651.                 &missing_trailing_dot(shift(@TXTlist), $zone);
  652.         &check_alias($name, $zone);
  653.         }
  654. }
  655.  
  656.  
  657. sub SOA_RR {
  658.     local($zone, $origin) = @_;
  659.  
  660.     $SOA{$zone} = &add_list($SOA{$zone}, &tolower($origin));
  661. }
  662.  
  663.  
  664. sub NS_RR {
  665.     local($zone, $name, $server) = @_;
  666.  
  667.  
  668.     $NS{$zone} = &add_list($NS{$zone}, join($ELEMsep1, &tolower($name), 
  669.                         &tolower($server)));
  670. }
  671.  
  672.  
  673. sub A_RR {
  674.         local($zone, $name, $address) = @_;
  675.  
  676.     $A{$zone}         = &add_list($A{$zone}, 
  677.                     join($ELEMsep1, $name, $address));
  678.  
  679.     $Addresses{$name} = &add_list($Addresses{$name}, $address);
  680.  
  681.     # don't save duplicates nor names for 127.0.0.1
  682.     if (!&in($name, $Names{$address}, $LISTsep) && 
  683.         !&is_reserved_name($address, $zone)) {
  684.         $Names{$address} = &add_list($Names{$address}, $name);
  685.     }
  686. }
  687.  
  688.  
  689. sub PTR_RR {
  690.     local($zone, $address, $name) = @_;
  691.  
  692.     $PTR{$zone} = &add_list($PTR{$zone}, join($ELEMsep1, $address, $name));
  693.  
  694.     # don't save duplicates nor names for 1.0.0.127.in-addr.arpa
  695.     if (!&in($name, $RevNames{$address}, $LISTsep) &&
  696.         !&is_reserved_name($address, $zone)) {
  697.         $RevNames{$address} = &add_list($RevNames{$address}, $name);
  698.     }
  699. }
  700.  
  701.  
  702. sub CNAME_RR {
  703.         local($zone, $name, $cname) = @_;
  704.  
  705.     $CNAME{$zone} = &add_list($CNAME{$zone}, 
  706.                   join($ELEMsep1, 
  707.                        &tolower($name), &tolower($cname)));
  708.  
  709.     $IsAlias{$name}  = 1;
  710. }
  711.  
  712.  
  713. sub WKS_RR {
  714.         local($zone, $name, $address) = @_;
  715.  
  716.     $WKS{$zone} = &add_list($WKS{$zone}, 
  717.               join($ELEMsep1, &tolower($name), $address));
  718. }
  719.  
  720.  
  721. sub HINFO_RR {
  722.         local($zone, $name) = @_,
  723.  
  724.         $HINFO{$zone} = &add_list($HINFO{$zone}, &tolower($name));
  725. }
  726.  
  727.  
  728. sub TXT_RR {
  729.     local($zone, $name) = @_,
  730.  
  731.     $TXT{$zone} = &add_list($TXT{$zone}, &tolower($name));
  732. }
  733.  
  734.  
  735. sub MX_RR {
  736.     local($zone, $name, $pointer) = @_;
  737.     local($n);
  738.  
  739.     $MX{$zone} = &add_list($MX{$zone}, join ($ELEMsep1, $name, $pointer));
  740. }
  741.